/*
 *  SoundTester.cpp
 *  SoundController0002
 *
 *  Created by jiro on 11/06/12.
 *  Copyright 2011 jiro music. All rights reserved.
 *
 */

#include "SoundTester.h"

#include "../Sound.h"
#include "../HarmonicSystem.h"
#include "../../../sc/Tester/CustomAssert.h"
#include "../../../sc/Common/WellTemperament.h"
#include "../../../sc/AllExceptions.h"

namespace sc
{
namespace hs
{
	void SoundTester::TestAll()
	{
		Test_Note000();

		Test_GetHarmonics000();

		Test_GetHarmonics001();

		Test_GetHarmonicsAmplitude000();
		Test_GetHarmonicsAmplitude001();
		
		Test_ContainHarmonics000();

		Test_GetAllHarmonics000();

		Test_GetNearbyWellTemperamentNotes000();
		Test_GetNearbyWellTemperamentNotes001();
		Test_GetNearbyWellTemperamentNotes002();

	}

	void SoundTester::Test_Note000()
	{
		Sound note( Sound::SawWave, ::sc::Note::A4 );
		AssertEqual( note.GetFrequency(), 440 );
		AssertEqual( note.GetWaveType(), Sound::SawWave );
	}

	void SoundTester::Test_GetHarmonics000()
	{
		Sound note( Sound::SawWave, ::sc::Note::A4 );
		double freq = WellTemperament::GetFrequency( ::sc::Note::A4 ); 
		try {
			note.GetHarmonics( 0 );
//			AssertFalse( true );
		} catch ( InvalidParameterException& e ) {
			AssertTrue( true );
		} catch ( ... ) {
			AssertFalse( true );
		}
		AssertEqual( note.GetHarmonics( 1 ), freq );
		AssertEqual( note.GetHarmonics( 2 ), 2 * freq );
		AssertEqual( note.GetHarmonics( 3 ), 3 * freq );

	}

	void SoundTester::Test_GetHarmonics001()
	{
		Sound note( Sound::SawWave, ::sc::Note::A4 );
		double freq = WellTemperament::GetFrequency( ::sc::Note::A4 ); 
		try {
			note.GetHarmonics( 0 );
//			AssertFalse( true );
		} catch ( InvalidParameterException& e ) {
			AssertTrue( true );
		} catch ( ... ) {
			AssertFalse( true );
		}
		AssertEqual( note.GetHarmonics( -1 ), freq );
		AssertEqual( note.GetHarmonics( -2 ), freq / 2.0 );
		AssertEqual( note.GetHarmonics( -3 ), freq / 3.0 );
	}

	void SoundTester::Test_GetHarmonicsAmplitude000()
	{
		Sound note( Sound::SquareWave, ::sc::Note::A4 );
		try
		{
			note.GetHarmonicAmplitude( 0 );
//			AssertFalse( true );
		}
		catch ( InvalidParameterException& r )
		{
			AssertTrue( true );
		}
		catch ( ... )
		{
			AssertFalse( true );
		}
		AssertEqual( note.GetHarmonicAmplitude( 1 ), 1 );
		AssertEqual( note.GetHarmonicAmplitude( 2 ), 0 / 2.0 );
		AssertEqual( note.GetHarmonicAmplitude( 3 ), 1 / 3.0 );

		AssertEqual( note.GetHarmonicAmplitude( -1 ), 1 );
		AssertEqual( note.GetHarmonicAmplitude( -2 ), 0 / 2.0 );
		AssertEqual( note.GetHarmonicAmplitude( -3 ), 1 / 3.0 );
	}

	void SoundTester::Test_GetHarmonicsAmplitude001()
	{
		Sound note( Sound::TriangleWave, ::sc::Note::A4 );
		try
		{
			note.GetHarmonicAmplitude( 0 );
//			AssertFalse( true );
		}
		catch ( InvalidParameterException& r )
		{
			AssertTrue( true );
		}
		catch ( ... )
		{
			AssertFalse( true );
		}
		AssertEqual( note.GetHarmonicAmplitude( 1 ), 1 );
		AssertEqual( note.GetHarmonicAmplitude( 2 ), 0 / 4.0 );
		AssertEqual( note.GetHarmonicAmplitude( 3 ), 1 / 9.0 );

		AssertEqual( note.GetHarmonicAmplitude( -1 ), 1 );
		AssertEqual( note.GetHarmonicAmplitude( -2 ), 0 / 4.0 );
		AssertEqual( note.GetHarmonicAmplitude( -3 ), 1 / 9.0 );
	}

	void SoundTester::Test_ContainHarmonics000()
	{
		::sc::Note::MidiNumber number = ::sc::Note::A4;
		double freq = WellTemperament::GetFrequency( number );
		Sound note( Sound::TriangleWave, number );
		AssertEqual( note.ContainHarmonics( 1 * freq ), true );
		AssertEqual( note.ContainHarmonics( 2 * freq ), true );
		AssertEqual( note.ContainHarmonics( 3 * freq ), true );
		AssertEqual( note.ContainHarmonics( 4 * freq ), true );

		AssertEqual( note.ContainHarmonics( 1 * freq + 1 ), false );
		AssertEqual( note.ContainHarmonics( 2 * freq - 10 * WellTemperament::calculationError ), false );
		AssertEqual( note.ContainHarmonics( 3 * freq + WellTemperament::calculationError ), true );
		AssertEqual( note.ContainHarmonics( 4 * freq - WellTemperament::calculationError ), true );

	}

	void SoundTester::Test_GetAllHarmonics000()
	{
		::sc::Note::MidiNumber number = sc::Note::MidiNumberMute;
		Sound sound( Sound::TriangleWave, number );
		std::vector< double > harmonics;
		sound.GetAllHarmonics( harmonics );

		AssertEqual( harmonics.size(), 0 );
//		AssertEqual( harmonics.size(), HarmonicSystem::HarmonicsCountMax );
//		for ( int i = 0; i < harmonics.size(); i++ )
//		{
//			std::string s;
//			s.append( "i = %d", i );
//			AssertEqualWithMessage( harmonics[ i ], ( i + 1 ) * freq, s );
//		}
	}

	void SoundTester::Test_GetNearbyWellTemperamentNotes000()
	{
		Sound sound( Sound::SawWave, sc::Note::A4 );
		const Sound::NearbyWellTemperamentNotes& nearbyNotes = sound.GetNearbyWellTemperamentNotes();

		AssertEqual( nearbyNotes.size(), 20 );

//		std::cout << nearbyNotes.size() << endl;
//		std::cout << Sound::ToString( nearbyNotes, -1, false, true, false ) << endl;

		Sound::NearbyWellTemperamentNotes::const_iterator iter;

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 3 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E6 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 6 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E7 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 9 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::B7 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 12 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E8 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 19 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::C9 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A4, 24 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E9 );
	}

	void SoundTester::Test_GetNearbyWellTemperamentNotes001()
	{
		Sound sound( Sound::SawWave, sc::Note::A3 );
		const Sound::NearbyWellTemperamentNotes& nearbyNotes = sound.GetNearbyWellTemperamentNotes();

		AssertEqual( nearbyNotes.size(), 37 );

//		std::cout << nearbyNotes.size() << endl;
//		std::cout << Sound::ToString( nearbyNotes, -1, false, true, false ) << endl;
/*
note: F#3(184.997[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=35.0028[Hz], 0.0285692[s/howl]
note: G3(195.998[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=24.0023[Hz], 0.0416627[s/howl]
note: G#3(207.652[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=12.3477[Hz], 0.0809871[s/howl]
note: A3(220[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=0[Hz], inf[s/howl]
note: A#3(233.082[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=13.0819[Hz], 0.0764416[s/howl]
note: B3(246.942[Hz]) is near by A3(220[Hz])'s 1th(220[Hz]), ∂=26.9417[Hz], 0.0371173[s/howl]

*/
		Sound::NearbyWellTemperamentNotes::const_iterator iter;

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 1 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::FSharp3 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::G3 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::GSharp3 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::A3 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::ASharp3 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::B3 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 3 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::DSharp5 );
		
		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E5 );

		iter++;
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::F5 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 5 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::CSharp6 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 9 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::B6 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 12 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E7 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 17 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::ASharp7 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 18 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::B7 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 19 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::C8 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 24 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E8 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 38 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::C9 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 48 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::E9 );

		iter = nearbyNotes.find( HarmonicSound( Sound::SingleSineWave, sc::Note::A3, 57 ) );
		AssertTrue( iter != nearbyNotes.end() );
		AssertEqual( iter->second, sc::Note::G9 );
	}

	void SoundTester::Test_GetNearbyWellTemperamentNotes002()
	{
//		AssertTrue( false );
	}

}
}
